//-------------------------------------------------------------------
//	Copyright (c) 2012-2014 Zhirnov Andrey
//	This file is part of the "UXGEN-ES" project.
//	See copyright notice in "Engine.h".
//-------------------------------------------------------------------

#pragma once

namespace MetaData
{

# ifdef __UX_DEBUG__
#	define FILE_RW_BEGIN()				bool	__rw_res = true
#	define FILE_RW_CHECK( _op )			__rw_res &= _op
#	define FILE_RW_RETURN()				CHECK_ERR( __rw_res ); return true
# else
#	define FILE_RW_BEGIN()				
#	define FILE_RW_CHECK( _op )			_op;
#	define FILE_RW_RETURN()				return true
# endif


	//
	// Utils
	//

	struct MetaDataUtils
	{
		// Save //
		template <typename T>
		inline static
		bool Save (const WFilePtr &file, const T &value)
		{
			FILE_RW_BEGIN();
			FILE_RW_CHECK( file->Write( value ) );
			FILE_RW_RETURN();
		}

		inline static
		bool Save (const WFilePtr &file, const string &value)
		{
			FILE_RW_BEGIN();
			FILE_RW_CHECK( file->Write( (Engine::UXTypes::uint) value.Count() ) );
			FILE_RW_CHECK( file->Write( value.cstr(), value.Size() ) );
			FILE_RW_RETURN();
		}

		template <typename T, typename C, typename A>
		inline static
		bool Save (const WFilePtr &file, const array<T,C,A> &value)
		{
			FILE_RW_BEGIN();
			FILE_RW_CHECK( file->Write( (Engine::UXTypes::uint) value.Count() ) );

			FOR( i, value ) {
				FILE_RW_CHECK( Save( file, value[i] ) );
			}
			FILE_RW_RETURN();
		}
		
		template <typename K, typename T, typename S, typename A>
		inline static
		bool Save (const WFilePtr &file, const map<K,T,S,A> &value)
		{
			FILE_RW_BEGIN();
			FILE_RW_CHECK( file->Write( (Engine::UXTypes::uint) value.Count() ) );

			FOR( i, value )
			{
				FILE_RW_CHECK( Save( file, value[i].first ) );
				FILE_RW_CHECK( Save( file, value[i].second ) );
			}
			FILE_RW_RETURN();
		}
		
		template <typename T, typename C, typename A>
		inline static
		bool _FastSaveArray (const WFilePtr &file, const array<T,C,A> &value)
		{
			FILE_RW_BEGIN();

			if ( not value.Empty() )
			{
				FILE_RW_CHECK( file->Write( (Engine::UXTypes::uint) value.Count() ) );
				FILE_RW_CHECK( file->Write( value.ptr(), value.Size() ) );
			}
			else
			{
				FILE_RW_CHECK( file->Write( (Engine::UXTypes::uint) 0 ) );
			}
			FILE_RW_RETURN();
		}


		// Load //
		template <typename T>
		inline static
		bool Load (const RFilePtr &file, T &value)
		{
			FILE_RW_BEGIN();
			FILE_RW_CHECK( file->Read( value ) );
			FILE_RW_RETURN();
		}

		inline static
		bool Load (const RFilePtr &file, string &value)
		{
			FILE_RW_BEGIN();
			Engine::UXTypes::uint len = 0;
			FILE_RW_CHECK( file->Read( len ) );

			ASSERT( len > 0 );
			value.Reserve( len );
			value.SetLength( len-1 );

			FILE_RW_CHECK( file->Read( value.ptr(), value.Size() ) );
			FILE_RW_RETURN();
		}
		
		template <typename T, typename C, typename A>
		inline static
		bool Load (const RFilePtr &file, array<T,C,A> &value)
		{
			FILE_RW_BEGIN();
			Engine::UXTypes::uint	count = 0;

			FILE_RW_CHECK( file->Read( count ) );
			value.Resize( count, false );
			
			FOR( i, value ) {
				FILE_RW_CHECK( Load( file, value[i] ) );
			}
			FILE_RW_RETURN();
		}
		
		template <typename K, typename T, typename S, typename A>
		inline static
		bool Load (const RFilePtr &file, map<K,T,S,A> &value)
		{
			FILE_RW_BEGIN();
			Engine::UXTypes::uint	count = 0;

			FILE_RW_CHECK( file->Read( count ) );
			value.Reserve( count );

			for (Engine::UXTypes::uint i = 0; i < count; ++i)
			{
				TPair<K,T>	pair;

				Load( file, pair.first );
				Load( file, pair.second );

				value.Add( pair );
			}
			FILE_RW_RETURN();
		}
		
		template <typename T, typename C, typename A>
		inline static
		bool _FastLoadArray (const RFilePtr &file, array<T,C,A> &value)
		{
			FILE_RW_BEGIN();
			Engine::UXTypes::uint	count = 0;

			FILE_RW_CHECK( file->Read( count ) );
			value.Resize( count, false );
			
			FILE_RW_CHECK( file->Read( value.ptr(), value.Size() ) );
			FILE_RW_RETURN();
		}
		

		// Copy //
		template <typename T0, typename T1>
		inline static
		void Copy (T0 &left, T1 &right, const EngineSubSystemsRef ess)
		{
			left = (T0) right;
		}
		
		template <typename T, typename C, typename A>
		inline static
		void Copy (array<T,C,A> &left, array<T,C,A> &right)
		{
			left.SetMem( right );
		}

		inline static
		void Copy (string &left, string &right, const EngineSubSystemsRef ess)
		{
			left.SwapMem( right );
			right.Clear();
		}


		// Init Meta Data //
		template <typename T>
		inline static
		void InitMetaData (const T &obj)
		{
		}
	};


	



#	define METADATAUTILS_OPT_ARRAYS( _arr ) \
		template <> \
		inline bool MetaDataUtils::Save<> (const WFilePtr &file, const _arr &value) \
		{ \
			return _FastSaveArray( file, value ); \
		} \
		\
		template <> \
		inline bool MetaDataUtils::Load<> (const RFilePtr &file, _arr &value) \
		{ \
			return _FastLoadArray( file, value ); \
		}

	METADATAUTILS_OPT_ARRAYS( uint8_array_t );
	METADATAUTILS_OPT_ARRAYS( uint16_array_t );
	METADATAUTILS_OPT_ARRAYS( uint32_array_t );
	METADATAUTILS_OPT_ARRAYS( uint64_array_t );

	METADATAUTILS_OPT_ARRAYS( int8_array_t );
	METADATAUTILS_OPT_ARRAYS( int16_array_t );
	METADATAUTILS_OPT_ARRAYS( int32_array_t );
	METADATAUTILS_OPT_ARRAYS( int64_array_t );

	METADATAUTILS_OPT_ARRAYS( float_array_t );
	METADATAUTILS_OPT_ARRAYS( double_array_t );

	METADATAUTILS_OPT_ARRAYS( bool_array_t );
	METADATAUTILS_OPT_ARRAYS( char_array_t );
	METADATAUTILS_OPT_ARRAYS( wchar_array_t );

#	undef METADATAUTILS_OPT_ARRAYS
	

	/*template <>
	inline void MetaDataUtils::Save<> (const WFilePtr &file, const variant_array_t &value)
	{
		STATIC_WARNING( "variant array not supported!" );
	}
	
	template <>
	inline void MetaDataUtils::Load<> (const RFilePtr &file, variant_array_t &value)
	{
		STATIC_WARNING( "variant array not supported!" );
	}*/

}	// MetaData
